From: kfraser@localhost.localdomain Date: Mon, 23 Oct 2006 10:20:37 +0000 (+0100) Subject: [NET] back: Fix packet queuing so that packets are drained if the X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~15585^2~22 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=61ca72df6f060ac731e5d493453a05f9c9b9833c;p=xen.git [NET] back: Fix packet queuing so that packets are drained if the interface is blocked for longer than 500ms. This avoids deadlock situations where interfaces cannot be destroyed because some other dormant interface is holding resources. Signed-off-by: Christopher Clark Signed-off-by: Keir Fraser --- diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h index 34dd998663..367c008d3b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h @@ -92,6 +92,9 @@ typedef struct netif_st { unsigned long remaining_credit; struct timer_list credit_timeout; + /* Enforce draining of the transmit queue. */ + struct timer_list tx_queue_timeout; + /* Miscellaneous private stuff. */ struct list_head list; /* scheduling list */ atomic_t refcnt; @@ -119,6 +122,8 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref, void netif_xenbus_init(void); +#define netif_schedulable(dev) (netif_running(dev) && netif_carrier_ok(dev)) + void netif_schedule_work(netif_t *netif); void netif_deschedule_work(netif_t *netif); diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index 78aa4cd8c5..c56013945b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -44,12 +44,11 @@ * For example, consider a packet that holds onto resources belonging to the * guest for which it is queued (e.g., packet received on vif1.0, destined for * vif1.1 which is not activated in the guest): in this situation the guest - * will never be destroyed, unless vif1.1 is taken down (which flushes the - * 'tx_queue'). - * - * Only set this parameter to non-zero value if you know what you are doing! + * will never be destroyed, unless vif1.1 is taken down. To avoid this, we + * run a timer (tx_queue_timeout) to drain the queue when the interface is + * blocked. */ -static unsigned long netbk_queue_length = 0; +static unsigned long netbk_queue_length = 32; module_param_named(queue_length, netbk_queue_length, ulong, 0); static void __netif_up(netif_t *netif) @@ -62,7 +61,6 @@ static void __netif_down(netif_t *netif) { disable_irq(netif->irq); netif_deschedule_work(netif); - del_timer_sync(&netif->credit_timeout); } static int net_open(struct net_device *dev) @@ -153,8 +151,11 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle) netif->credit_bytes = netif->remaining_credit = ~0UL; netif->credit_usec = 0UL; init_timer(&netif->credit_timeout); + /* Initialize 'expires' now: it's used to track the credit window. */ netif->credit_timeout.expires = jiffies; + init_timer(&netif->tx_queue_timeout); + dev->hard_start_xmit = netif_be_start_xmit; dev->get_stats = netif_be_get_stats; dev->open = net_open; @@ -319,11 +320,23 @@ err_rx: return err; } -static void netif_free(netif_t *netif) +void netif_disconnect(netif_t *netif) { + if (netif_carrier_ok(netif->dev)) { + rtnl_lock(); + netif_carrier_off(netif->dev); + if (netif_running(netif->dev)) + __netif_down(netif); + rtnl_unlock(); + netif_put(netif); + } + atomic_dec(&netif->refcnt); wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0); + del_timer_sync(&netif->credit_timeout); + del_timer_sync(&netif->tx_queue_timeout); + if (netif->irq) unbind_from_irqhandler(netif->irq, netif); @@ -337,16 +350,3 @@ static void netif_free(netif_t *netif) free_netdev(netif->dev); } - -void netif_disconnect(netif_t *netif) -{ - if (netif_carrier_ok(netif->dev)) { - rtnl_lock(); - netif_carrier_off(netif->dev); - if (netif_running(netif->dev)) - __netif_down(netif); - rtnl_unlock(); - netif_put(netif); - } - netif_free(netif); -} diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 08c075ac27..5706322a8f 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -264,6 +264,13 @@ static inline int netbk_queue_full(netif_t *netif) ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed); } +static void tx_queue_callback(unsigned long data) +{ + netif_t *netif = (netif_t *)data; + if (netif_schedulable(netif->dev)) + netif_wake_queue(netif->dev); +} + int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_t *netif = netdev_priv(dev); @@ -271,20 +278,13 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(skb->dev != dev); /* Drop the packet if the target domain has no receive buffers. */ - if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev))) + if (unlikely(!netif_schedulable(dev) || netbk_queue_full(netif))) goto drop; - if (unlikely(netbk_queue_full(netif))) { - /* Not a BUG_ON() -- misbehaving netfront can trigger this. */ - if (netbk_can_queue(dev)) - DPRINTK("Queue full but not stopped!\n"); - goto drop; - } - - /* Copy the packet here if it's destined for a flipping - interface but isn't flippable (e.g. extra references to - data) - */ + /* + * Copy the packet here if it's destined for a flipping interface + * but isn't flippable (e.g. extra references to data). + */ if (!netif->copying_receiver && !is_flippable_skb(skb)) { struct sk_buff *nskb = netbk_copy_skb(skb); if ( unlikely(nskb == NULL) ) @@ -305,8 +305,19 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) netif->rx.sring->req_event = netif->rx_req_cons_peek + netbk_max_required_rx_slots(netif); mb(); /* request notification /then/ check & stop the queue */ - if (netbk_queue_full(netif)) + if (netbk_queue_full(netif)) { netif_stop_queue(dev); + /* + * Schedule 500ms timeout to restart the queue, thus + * ensuring that an inactive queue will be drained. + * Packets will be immediately be dropped until more + * receive buffers become available (see + * netbk_queue_full() check above). + */ + netif->tx_queue_timeout.data = (unsigned long)netif; + netif->tx_queue_timeout.function = tx_queue_callback; + __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2); + } } skb_queue_tail(&rx_queue, skb); @@ -706,6 +717,7 @@ static void net_rx_action(unsigned long unused) } if (netif_queue_stopped(netif->dev) && + netif_schedulable(netif->dev) && !netbk_queue_full(netif)) netif_wake_queue(netif->dev); @@ -763,8 +775,7 @@ static void add_to_net_schedule_list_tail(netif_t *netif) spin_lock_irq(&net_schedule_list_lock); if (!__on_net_schedule_list(netif) && - likely(netif_running(netif->dev) && - netif_carrier_ok(netif->dev))) { + likely(netif_schedulable(netif->dev))) { list_add_tail(&netif->list, &net_schedule_list); netif_get(netif); } @@ -1358,7 +1369,7 @@ irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs) add_to_net_schedule_list_tail(netif); maybe_schedule_tx_action(); - if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif)) + if (netif_schedulable(netif->dev) && !netbk_queue_full(netif)) netif_wake_queue(netif->dev); return IRQ_HANDLED; diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c index c61821c8f9..b81042d701 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @@ -328,7 +328,7 @@ static void connect(struct backend_info *be) /* May not get a kick from the frontend, so start the tx_queue now. */ if (!netbk_can_queue(be->netif->dev)) - netif_start_queue(be->netif->dev); + netif_wake_queue(be->netif->dev); }